<?php

namespace dk\core;
use Exception;

class App{
    use \dk\traits\Singleton;
    
    use EventManager;

    /**
     * @var Router
     */
    private $router;

    /**
     * @var Dispatcher
     */
    private $dispatcher;

    /**
     * @var View
     */
    private $view;

    /**
     * @param \dk\core\Dispatcher $dispatcher
     */
    public function setDispatcher($dispatcher) {
        $this->dispatcher = $dispatcher;
    }

    /**
     * @param \dk\core\Router $router
     */
    public function setRouter($router) {
        $this->router = $router;
    }

    /**
     * @param \dk\core\View $view
     */
    public function setView($view) {
        $this->view = $view;
    }

    /**
     *
     */
    private function __construct(){
    }

    /**
     * main()
     */
    function run(){
        $router = $this->getRouter();
        $this->trigger('initRouter', $router);
//        try{
            $action = $this->getAction($router);
            if($action instanceof Action){
                $view = $this->getView();
                $this->trigger('initView', $view, $router);

                $action->setDocument($view);
                $action->regPlug('url', array($router, 'build'));
                
                $this->trigger('initAction', $action, $router);
                $action->execute();
                $view->render();
            } else {
                $action->main();
            }
        /*} catch(Exception $e){
            isset($view) && $view->setError($e);
        }*/
    }

    /**
     * @return Router
     */
    private function getRouter(){
        if(!isset($this->router)){
            $this->router = Router::getInstance();
        }
        return $this->router;
    }

    private function getView(){
        if(!isset($this->view)){
            $view = new View();
            $this->view = $view;
            
        }

        return $this->view;
    }

    private function getDispatcher($router){
        if(!isset($this->dispatcher)){
            $this->dispatcher = new Dispatcher($router);
        }
        return $this->dispatcher;
    }

    /**
     * @param Router $router
     * @return Action
     * @throws \Exception
     */
    private function getAction($router){
        $dispatcher = $this->getDispatcher($router);
        $this->trigger('initDispatcher', $dispatcher);

        $action = $dispatcher->getAction();
        if($action){
            return $action;
        }

        $rs = $this->trigger('InvalidAction', $dispatcher);
        if($rs->getEvent()->isPropagationStopped()){
            return $rs->last();
        }

        $task = $router->getTask();
        throw(new Exception("Invalid action({$task}})"));
    }
}